package bigo;

import bigo.data.MatrixMeta;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileContext;
import org.apache.hadoop.fs.FsShell;
import org.apache.hadoop.fs.Options.Rename;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

/**
 *
 * @author Song Liu (sl9885@bristol.ac.uk)
 */
public class NMFDriver extends Configured implements Tool {

    private static String archiveFolder = "archive/";

    public int run(String[] args) throws Exception {
        String A = args[0], W = args[1], HT = args[2],
                W_T = args[1] + "_T", H = args[2] + "_T";

        String rowBlocks = getConf().get("NMF.blocks.row", "5");
        String columnBlocks = getConf().get("NMF.blocks.col", "5");
        String kBlocks = getConf().get("NMF.blocks.k", "1");

        FileContext fs = FileContext.getFileContext(getConf());
        FsShell shell = new FsShell(getConf());

        int i = Integer.parseInt(args[3]);
        int j = Integer.parseInt(args[4]);
        int k = Integer.parseInt(args[5]);

        int res = ToolRunner.run(getConf(), new MultiplicationDriver(),
                new String[]{W_T, A, "XT", k + "", i + "", j + "", kBlocks, rowBlocks, columnBlocks});
        if (res != 0) {
            return res;
        }

        res = ToolRunner.run(getConf(), new MultiplicationDriver(),
                new String[]{W_T, W, "c", k + "", i + "", k + "", kBlocks, rowBlocks, kBlocks});

        if (res != 0) {
            return res;
        }

        //dowload the matrix c
        shell.run(new String[]{"-get", "c", "clocal"});
        res = ToolRunner.run(getConf(), new LargeASmallBMultiplicationDriver(
                new MatrixMeta(HT, k, j, true),
                new MatrixMeta("clocal", k, k),
                new MatrixMeta("YT", k, j)),
                new String[]{});
        FileContext.getLocalFSFileContext().delete(new Path("clocal"), true);

        if (res != 0) {
            return res;
        }
        res = ToolRunner.run(getConf(), new NMFAgreegationDriver(
                new MatrixMeta("XT", j, k),
                new MatrixMeta("YT", j, k),
                new MatrixMeta(HT, j, k),
                new MatrixMeta("output", j, k)),
                new String[]{});

        if (res != 0) {
            return res;
        }

        //update the HT matrix
        //fs.delete(new Path(HT), true);
        //save the historical data for analysis.
        fs.rename(new Path(HT), new Path(archiveFolder
                + HT + System.currentTimeMillis()), Rename.NONE);

        fs.rename(new Path("output"), new Path(HT), Rename.OVERWRITE);

        System.out.println("updating W");
        res = ToolRunner.run(getConf(), new MultiplicationDriver(),
                new String[]{A, HT, "X", i + "", j + "", k + "", rowBlocks, columnBlocks, kBlocks});
        if (res != 0) {
            return res;
        }
        res = ToolRunner.run(getConf(), new MultiplicationDriver(),
                new String[]{H, HT, "c", k + "", j + "", k + "", kBlocks, columnBlocks, kBlocks});

        if (res != 0) {
            return res;
        }

        //dowload the matrix c
        shell.run(new String[]{"-get", "c", "clocal"});
        res = ToolRunner.run(getConf(), new LargeASmallBMultiplicationDriver(
                new MatrixMeta(W, i, k),
                new MatrixMeta("clocal", k, k),
                new MatrixMeta("Y", i, k)),
                new String[]{});
        FileContext.getLocalFSFileContext().delete(new Path("clocal"), true);

        if (res != 0) {
            return res;
        }
        res = ToolRunner.run(getConf(), new NMFAgreegationDriver(
                new MatrixMeta("X", i, k),
                new MatrixMeta("Y", i, k),
                new MatrixMeta(W, i, k),
                new MatrixMeta("output", j, k)),
                new String[]{});

        if (res != 0) {
            return res;
        }

        //update W
        // save the historical data for analysis
        //fs.delete(new Path(W), true);
        fs.rename(new Path(W), new Path(archiveFolder +
                W + System.currentTimeMillis()),
                Rename.NONE);
        fs.rename(new Path("output"), new Path(W), Rename.OVERWRITE);
        return res;
    }

    public static void main(String[] args) throws Exception {
        int i = 0;
        while (true) {
            ToolRunner.run(new NMFDriver(), args);
            i++;
            System.out.println(i);
            if (i > 0) {
                return;
            }
        }
    }
}
